import gtk

from ui import *
from soap import *

from ui.GladeBase import GladeBase
from utils import string_hook, logger, envir, check_authorization, AUTHOR

NO_ENTITY = -1

class ManageAuthor(GladeBase):
    
    def __init__(self, query=None, top_component=None):
        logger.debug("UI: %s instance created" % self.__class__)
        GladeBase.__init__(self, 'manage_author_frame', top_component)
        self._init_gui_components()
            
        # Setting up Author's list TreeView
        cell = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn('Authors')
        tvc.pack_start(cell, False)
        cel2 = gtk.CellRendererText()
        tvc.pack_end(cel2, False)
        tvc.set_attributes(cell,text=2)
        tvc.add_attribute(cel2,"text",1)
        self.authors_treeview.append_column(tvc)
        
        self.author_list = gtk.ListStore(int, str, str, object)
        self.author_list.set_sort_column_id(2, gtk.SORT_ASCENDING)
        self.author_frame_hpaned.set_position(400)
        
        self.entity_key = NO_ENTITY
        id = None
        
        if check_authorization(envir.get_user(), AUTHOR):
            self.delete_button.set_sensitive(False)
            self.new_button.set_sensitive(False)
            id = envir.get_user()['id']
            
        try:
            authors = client.get_authors(id)
            for author in authors:
                self._append_author(author)
                
            if id: self._load_to_gui(authors[0])
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
            
        self.authors_treeview.set_model(self.author_list)
    
    def _append_author(self, author):
        """
        Add an author to the list
        """
        self.author_list.append([author.id, author.name, author.surname, author])
        
    def _update_author(self, row, author):
        """
        Update an author row in model with new value
        """
        self.author_list.set(row.iter, 1, author.name, 2, author.surname, 3, author)
        
    def _init_gui_components(self):
        """
        Intialize gui components as needed. This is useful in the contructor or 
        binded with particular actions (for instance, a "clear" button, or "new" button) 
        """
        self.name_entry.set_text("")
        self.surname_entry.set_text("")
        self.address_entry.set_text("")
        self.city_entry.set_text("")
        self.prov_entry.set_text("")
        self.postal_entry.set_text("")
        self.country_entry.set_text("")
        self.address_checkbutton.set_active(False)
        self.apply_button.set_sensitive(False)
    
    def _retrieve_components(self):
        """
        Retrieve all used gui components from builder. This method is called in the
        GladeBase constructor
        """
        self.get_from_builder('authors_treeview')
        self.get_from_builder('name_entry')
        self.get_from_builder('surname_entry')
        self.get_from_builder('address_checkbutton')
        self.get_from_builder('address_frame')
        self.get_from_builder('address_entry')
        self.get_from_builder('city_entry')
        self.get_from_builder('prov_entry')
        self.get_from_builder('postal_entry')
        self.get_from_builder('country_entry')
        self.get_from_builder('apply_button')
        self.get_from_builder('delete_button')
        self.get_from_builder('new_button')
        self.get_from_builder('author_frame_hpaned')
        
    def _has_valid_data(self):
        """
        Formal control for data in the input form.
        @return: boolean. 'True' when data is valid
        """
        
        name = self.name_entry.get_text()
        surname = self.surname_entry.get_text()
        address = self.address_entry.get_text()
        city = self.city_entry.get_text()
        
        if not name:
            mandatory_data_error('Name', self.name_entry)
            return False
             
        if not surname:
            mandatory_data_error('Surname', self.surname_entry)
            return False
        
        # Perform address checks only when user choose to input address data
        if not self.address_checkbutton.get_active():
            return True
        
        if not address:
            mandatory_data_error('Address', self.address_entry)
            return False
        
        if not city:
            mandatory_data_error('City', self.city_entry)
            return False
        
        return True
    
    def _load_to_gui(self, author):
        self.entity_key = author.id
        
        self.name_entry.set_text(author.name)
        self.surname_entry.set_text(author.surname)
        
        # TODO: actually we only manage one address from the gui,
        #       which will be the first for default ordering
        try:
            address = author.addresses[0]
            self.address_checkbutton.set_active(True)
            self.address_entry.set_text(address.address)
            self.postal_entry.set_text(string_hook(address.postalcode))
            self.prov_entry.set_text(string_hook(address.province))
            self.city_entry.set_text(address.city)
            self.country_entry.set_text(string_hook(address.country))
        except (IndexError, TypeError):
            pass
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
        
        self.apply_button.set_sensitive(False)        
    
    def _save_data(self):
        """
        Save changes to db. 
        
        return: 'True' if data have been successfully saved 
        """
        if not self._has_valid_data():
            return False
        
        # manage Author data object
        if self.entity_key == NO_ENTITY:
            author = AuthorSoap()
        else:
            row = search(self.author_list, (0, self.entity_key))
            author = row[3]
        
        author.name = self.name_entry.get_text()
        author.surname = self.surname_entry.get_text()
        
        # manage Address data object
        address_is_active = self.address_checkbutton.get_active()
        try:
            address = author.addresses[0]
        except (IndexError, TypeError):
            address = None
        
        if address_is_active:
            if not address: 
                address = AddressSoap()
                author.addresses = []
                author.addresses.append(address)
            address.address = self.address_entry.get_text()
            address.postalcode = string_hook(self.postal_entry.get_text())
            address.province = string_hook(self.prov_entry.get_text())
            address.country = string_hook(self.country_entry.get_text())
            address.city = self.city_entry.get_text()
            address.type = 'head'
        elif address:
            author.addresses.remove(address)
        
        # save changes
        try:
            author.id = client.save_author(author)
            if not author.id > 0:
                raise Exception("Problem occurred on server during save")
            
            if self.entity_key == NO_ENTITY:
                self._append_author(author)
            else:
                # update row in author list
                row = search(self.author_list, (0, author.id))
                self._update_author(row, author)
            
            self.entity_key = author.id
            self.apply_button.set_sensitive(False)
            return True
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
            return False
    
    # Signals
    def on_new_button_clicked(self, object, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    session.rollback()
                    return
                
        self._init_gui_components()
        self.authors_treeview.get_selection().unselect_all()
        self.entity_key = NO_ENTITY
    
    def on_apply_button_clicked(self, object, data=None):
        self._save_data()
    
    def on_delete_button_clicked(self, object, data=None):
        (model, iter) = self.authors_treeview.get_selection().get_selected()
        if not iter:
            return 
        
        author = model.get_value(iter, 3)
        if author.books:
            res = get_save_dialog(self.get_top_component(), 
                                  "This author has books inserted, if you delete him,\n" \
                                  "he will be removed from the book's authors list.\nAre you sure?")
            if res != gtk.RESPONSE_OK:
                return 
        
        try:
            client.delete_author(author)
            model.remove(iter)
            
            self._init_gui_components()
            self.entity_key = NO_ENTITY
        except Exception as e:
            get_error_dialog(self.get_top_component(), e)
    
    def on_author_changed(self, object, data=None):
        self.apply_button.set_sensitive(True)
    
    def on_authors_treeview_row_activated(self, treeview, path, view_column, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(None, "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
        
        self._init_gui_components()
        
        self._load_to_gui(self.author_list[path][3])
        
    def on_address_checkbutton_toggled(self, object, data=None):
        self.address_frame.set_sensitive(object.get_active())
        self.on_author_changed(object, data)
